import { useCallback, useEffect, useMemo, useState, RefObject } from 'react';

// 定义全屏相关属性的联合类型
type FullscreenElementProperty =
  | 'fullscreenElement'
  | 'webkitFullscreenElement'
  | 'mozFullScreenElement'
  | 'msFullscreenElement';

// 修正全屏启用状态属性（仅保留布尔值属性）
type FullscreenEnabledProperty =
  | 'fullScreen'
  | 'webkitIsFullScreen'
  | 'webkitDisplayingFullscreen'
  | 'mozFullScreen'; // 移除 msFullscreenElement（它属于元素属性而非布尔状态）

// 定义全屏退出方法的联合类型
type ExitFullscreenMethod =
  | 'exitFullscreen'
  | 'webkitExitFullscreen'
  | 'webkitExitFullScreen'
  | 'webkitCancelFullScreen'
  | 'mozCancelFullScreen'
  | 'msExitFullscreen';

// 定义全屏请求方法的联合类型
type RequestFullscreenMethod =
  | 'requestFullscreen'
  | 'webkitRequestFullscreen'
  | 'webkitEnterFullscreen'
  | 'webkitEnterFullScreen'
  | 'webkitRequestFullScreen'
  | 'mozRequestFullScreen'
  | 'msRequestFullscreen';

const eventHandlers = [
  'fullscreenchange',
  'webkitfullscreenchange',
  'webkitendfullscreen',
  'mozfullscreenchange',
  'MSFullscreenChange',
];

const defaultDocument = typeof document !== 'undefined' ? window.document : undefined;

export const useFullscreen = (
  target?: HTMLElement | RefObject<HTMLElement> | undefined, // 修改类型
  options: {
    document?: Document;
    autoExit?: boolean;
  } = {},
) => {
  const { document = defaultDocument } = options;

  const targetRef = useMemo(() => {
    return target != null
      ? 'current' in target
        ? target.current
        : target // 检查是否是 Ref 对象
      : document == null
        ? null
        : document.querySelector('html');
  }, [target, document]);

  const [isFullscreen, setIsFullscreen] = useState(false);

  const requestMethod = useMemo<RequestFullscreenMethod | undefined>(() => {
    return [
      'requestFullscreen',
      'webkitRequestFullscreen',
      'webkitEnterFullscreen',
      'webkitEnterFullScreen',
      'webkitRequestFullScreen',
      'mozRequestFullScreen',
      'msRequestFullscreen',
    ].find(m => (document && m in document) || (targetRef && m in targetRef)) as
      | RequestFullscreenMethod
      | undefined;
  }, [document, targetRef]);

  const exitMethod = useMemo<ExitFullscreenMethod | undefined>(() => {
    return [
      'exitFullscreen',
      'webkitExitFullscreen',
      'webkitExitFullScreen',
      'webkitCancelFullScreen',
      'mozCancelFullScreen',
      'msExitFullscreen',
    ].find(m => (document && m in document) || (targetRef && m in targetRef)) as
      | ExitFullscreenMethod
      | undefined;
  }, [document, targetRef]);

  const fullscreenEnabled = useMemo(() => {
    return [
      'fullScreen',
      'webkitIsFullScreen',
      'webkitDisplayingFullscreen',
      'mozFullScreen',
      'msFullscreenElement',
    ].find(m => (document && m in document) || (targetRef && m in targetRef));
  }, [document, targetRef]);

  const fullscreenElementMethod = [
    'fullscreenElement',
    'webkitFullscreenElement',
    'mozFullScreenElement',
    'msFullscreenElement',
  ].find(m => document && m in document);

  const isSupported = useMemo(() => {
    return (
      targetRef &&
      document &&
      requestMethod !== void 0 &&
      exitMethod !== void 0 &&
      fullscreenEnabled !== void 0
    );
  }, [document, requestMethod, exitMethod, fullscreenEnabled, targetRef]);

  const isCurrentElementFullScreen = useCallback(() => {
    // 在使用的地方指定类型
    const fullscreenElementMethod: FullscreenElementProperty =
      document && 'fullscreenElement' in document
        ? 'fullscreenElement'
        : document && 'webkitFullscreenElement' in document
          ? 'webkitFullscreenElement'
          : document && 'mozFullScreenElement' in document
            ? 'mozFullScreenElement'
            : 'msFullscreenElement';

    if (fullscreenElementMethod) {
      // 使用类型断言解决索引问题
      return (
        (document == null
          ? void 0
          : (document as Document & { [key in FullscreenElementProperty]: HTMLElement | null })[
              fullscreenElementMethod
            ]) === targetRef
      );
    }
    return false;
  }, [document, fullscreenElementMethod, targetRef]);

  const isElementFullScreen = useCallback(() => {
    if (fullscreenEnabled) {
      // 处理document上的全屏属性
      if (document) {
        const docValue = document[fullscreenEnabled as keyof Document];
        if (docValue != null) {
          return Boolean(docValue); // 显式转换为布尔值
        }
      }
      // 处理目标元素上的全屏属性
      if (targetRef) {
        const target2 = targetRef as HTMLElement & {
          [key in FullscreenEnabledProperty]?: boolean | null;
        };
        const targetValue = target2[fullscreenEnabled as FullscreenEnabledProperty];
        if (targetValue != null) {
          return Boolean(targetValue); // 显式转换为布尔值
        }
      }
    }
    return false; // 默认返回false，确保始终返回boolean
  }, [document, fullscreenEnabled, targetRef]);

  const exit = async () => {
    if (!isSupported || !isFullscreen) return;
    if (exitMethod) {
      // 对 document 进行类型断言，允许使用 ExitFullscreenMethod 索引
      if (
        document &&
        (document as Document & { [key in ExitFullscreenMethod]: () => Promise<void> })[exitMethod]
      ) {
        await (document as Document & { [key in ExitFullscreenMethod]: () => Promise<void> })[
          exitMethod
        ]();
      } else {
        const target2 = targetRef;
        // 对 target2 进行类型断言，允许使用 ExitFullscreenMethod 索引
        if (
          target2 &&
          (target2 as HTMLElement & { [key in ExitFullscreenMethod]: () => Promise<void> })[
            exitMethod
          ]
        ) {
          await (target2 as HTMLElement & { [key in ExitFullscreenMethod]: () => Promise<void> })[
            exitMethod
          ]();
        }
      }
    }
    setIsFullscreen(false);
  };

  const enter = async () => {
    if (!isSupported || isFullscreen) return;
    if (isElementFullScreen()) {
      await exit();
    }
    const target2 = targetRef;
    // 对 target2 进行类型断言，允许使用 RequestFullscreenMethod 索引
    if (
      requestMethod &&
      target2 &&
      (target2 as HTMLElement & { [key in RequestFullscreenMethod]: () => Promise<void> })[
        requestMethod
      ]
    ) {
      await (target2 as HTMLElement & { [key in RequestFullscreenMethod]: () => Promise<void> })[
        requestMethod
      ]();
      setIsFullscreen(true);
    }
  };

  const toggle = async () => {
    if (isFullscreen) {
      await exit();
    } else {
      await enter();
    }
  };

  const handlerCallback = useCallback(() => {
    const isElementFull = isElementFullScreen();
    // 只有当前元素处于全屏时才更新状态
    if (isElementFull === isCurrentElementFullScreen()) {
      setIsFullscreen(isElementFull);
    }
  }, [isElementFullScreen, isCurrentElementFullScreen]);

  useEffect(() => {
    if (isSupported) {
      eventHandlers.forEach(event => {
        document?.addEventListener(event, handlerCallback);
      });
    }

    return () => {
      eventHandlers.forEach(event => {
        document?.removeEventListener(event, handlerCallback);
      });
    };
  }, [isSupported, document, handlerCallback]);

  return {
    isFullscreen,
    isSupported,
    enter,
    exit,
    toggle,
  };
};
